package cn.bxshey.general.aop;

import cn.bxshey.general.aop.note.Permissions;
import cn.bxshey.general.constant.JwtConstant;
import cn.bxshey.general.enums.HeaderEnum;
import cn.bxshey.general.enums.ResultEnum;
import cn.bxshey.general.exception.BusinessException;
import cn.bxshey.general.util.HttpUtils;
import cn.bxshey.general.util.JwtUtils;
import cn.bxshey.redis.constant.RedisConstant;
import cn.bxshey.redis.utils.RedisUtils;
import net.dreamlu.mica.ip2region.core.Ip2regionSearcher;
import net.dreamlu.mica.ip2region.core.IpInfo;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.mindrot.jbcrypt.BCrypt;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * @作者：不想说话而已
 * @Date：2023/12/1 16:29
 * 权限校验注解
 */
@Aspect //说明这是一个切面
@Component
@Order(1)
public class PermissionsAop {

    @Resource
    Ip2regionSearcher ip2regionSearcher;

    @Resource
    RedisUtils redisUtils;

    @Resource
    HttpUtils httpUtils;


    @Around("@annotation(permissions)")
    public Object permission(ProceedingJoinPoint joinPoint, Permissions permissions) throws Throwable {

        //远程调用不需要进行鉴权操作,判断请求头，如果有并正确则直接放行
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        List<String> feignToken = new ArrayList<>();
        Optional.ofNullable(requestAttributes).ifPresent((s) -> {
            HttpServletRequest request = requestAttributes.getRequest();
            feignToken.add(request.getHeader(HeaderEnum.HEADER_FEIGN.key));
        });
        if (feignToken.size() > 0 && feignToken.get(0).equals(HeaderEnum.HEADER_FEIGN.value)) {
            return joinPoint.proceed();
        }

        //获取IP、请求头token、ip归属地信息
        Map<String, String> request = httpUtils.getHttpInfo();

        //检查token
        Map<String, Object> jwtInfo = JwtUtils.checkToken(request.get(JwtConstant.ACCESS_TOKENS));
        //校验失败抛出异常
        Optional.ofNullable(jwtInfo).orElseThrow(() -> new BusinessException(ResultEnum.VERIFICATION_EXPIRES));
//        //判断 ,访问ip是否和令牌所携带的ip一致
//        IpInfo ipInfo = ip2regionSearcher.memorySearch( String.valueOf(jwtInfo.get("ip")));
//        IpInfo ipInfo2 = ip2regionSearcher.memorySearch( request.get("ip"));
//        String address = ipInfo.getAddress();
//        String address2 = ipInfo2.getAddress();
//        boolean checkToken = BCrypt.checkpw(request.get("ip"), String.valueOf(jwtInfo.get("ip")));
//        if (!checkToken) {
//            throw new BusinessException(ResultEnum.VERIFICATION_EXPIRES); //令牌无效，提示重新登录
//        }


        //检查权限
        Boolean permission = redisUtils.checkSetValue(RedisConstant.PERMISSIONS, String.valueOf(jwtInfo.get("uid")), permissions.url());
        //校验权限失败抛出异常
        Optional.ofNullable(permission ? true : null).orElseThrow(() -> new BusinessException(ResultEnum.ERROR_PERMISSION));


        //执行原接口的方法
        return joinPoint.proceed();
    }

}
